//工具函数
const { resolve } = require('path');
const { Readable } = require('stream');
//es-module-lexer是一个可以对 ES Module 语句进行词法分析的工具包
const { parse: esModuleParse } = require('es-module-lexer');
//magic-string这个库做一些字符串的魔术替换，这个库的目的就是在一些轻量级替换源代码的场景中替代 AST 这种过于庞大的解决方案
const MagicString = require('magic-string');

/**
 * 专门获取ctx.body响应的内容，如流(通过流的方式传递)
 * @param {*} bodyStream ctx.body的流
 */
async function readBodyStream(bodyStream) {
  //证明是可读的
  if (bodyStream instanceof Readable) {
    let res = '';

    return new Promise((resolve) => {
      //传输事件：读取 流 的块
      bodyStream.on('data', (chunk) => (res += chunk));

      //传输完毕时事件： 抛出拼接后的数据(流)
      bodyStream.on('end', () => resolve(res));
    });
  }

  //不可读时
  return bodyStream;
}

/**
 * 重写import路径实现指定读取目录里的依赖文件
 * @param {*} source js文件里的字符串代码
 * @returns 返回重写后的MagicString代码
 */
async function rewriteImports(source) {
  //解析某个JS文件里所有import关键字里引入的路径
  const res = esModuleParse(source);
  /**
   console.log(res);
   * [
   *   [
   *     { n: 'vue', s: 27, e: 30, ss: 0, se: 31, d: -1, a: -1 },
   *     { n: './App.vue', s: 51, e: 60, ss: 34, se: 61, d: -1, a: -1 }
   *   ],
   *   [],
   *   false
   * ]
   */

  const magicString = new MagicString(source);
  // console.log(magicString);
  //空的内容 MagicString {}

  const imports = res[0];

  if (imports.length > 0) {
    imports.forEach((_import) => {
      //解构获取s 和 e 字段的值
      const { s, e } = _import;

      //从代码起始位置到结束位置获取 依赖名称或路径
      let importId = source.slice(s, e);
      // console.log(importId);
      //'vue' 或 './App.vue'

      //排除 .开头 和 ./开头
      if (/^[^\.\/]/.test(importId)) {
        // console.log(importId);
        //vue

        //组装依赖路径
        importId = vueNodeModulePath('runtime-dom', moduleMapping(importId));
        // console.log(importId);
        // /node_modules/@vue/runtime-dom/dist/compiler-dom.esm-browser.js

        //重写 起始位置 结束位置 指定内容
        magicString.overwrite(s, e, importId);
      }
    });
  }

  //返回重写后的MagicString代码 实现指定读取目录里的依赖文件
  return magicString.toString();
}

/**
 * 根据依赖名称映射该依赖的读取目录路径
 * @param {*} importId 依赖名称
 * @returns 新的路径文件
 */
function moduleMapping(importId) {
  switch (importId) {
    case 'vue':
      //找到vue/compiler-dom依赖里的名称
      return 'runtime-dom.esm-browser.js';
    default:
      break;
  }
}

/**
 * 处理vue依赖目录里对应文件的路径
 * @param {*} package 依赖目录名称
 * @param {*} filename 文件名称
 * @returns 返回vue依赖目录里对应文件的路径
 */
function vueNodeModulePath(package, filename) {
  return `/node_modules/@vue/${package}/dist/${filename}`;
}

module.exports = {
  readBodyStream,
  rewriteImports,
  vueNodeModulePath
};
